package com.doctcloud.datacloud.service;

import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.doctcloud.common.core.domain.R;
import com.doctcloud.datacloud.entity.DeptDictEntity;
import com.doctcloud.datacloud.mapper.DeptDictEntityMapper;
import com.doctcloud.hisinfo.api.RemoteHisCommonService;
import com.doctcloud.hisinfo.histable.domain.comm.DeptDictDo;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.io.*;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 科室字典服务
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class DeptDictEntityService extends ServiceImpl<DeptDictEntityMapper, DeptDictEntity> {
    @Value("${sync.batch.size:500}")
    private int BATCH_SIZE;

    private final RemoteHisCommonService remoteHisCommonService;

    /**
     * 科室信息同步（初始化或增量更新）
     * 此方法会从远程服务获取最新的科室列表，并将本地数据库中不存在的科室信息插入。
     */
    @Transactional
    public void syncDeptDict() {
        log.info("--- 开始同步科室字典数据 ---");
        long startTime = System.currentTimeMillis();

        try {
            // 1. 从远程服务获取全量科室信息
            R<List<DeptDictDo>> remoteDeptListR = remoteHisCommonService.deptListByDB();
            if (remoteDeptListR == null || !R.isSuccess(remoteDeptListR) || CollectionUtils.isEmpty(remoteDeptListR.getData())) {
                log.warn("从远程服务获取科室列表失败或返回为空，同步任务终止。");
                return;
            }
            List<DeptDictDo> remoteDeptList = remoteDeptListR.getData();
            log.info("从远程服务获取到 {} 个科室信息。", remoteDeptList.size());

            // 2. 批量查询本地数据库中已存在的科室编码，以Set形式存储，便于快速比对
            Set<String> existingDeptCodes = this.list().stream() // 使用 this.list() 更简洁
                    .map(DeptDictEntity::getDeptCode)
                    .collect(Collectors.toSet());
            log.info("本地数据库中已存在 {} 个科室信息。", existingDeptCodes.size());

            // 3. 筛选出需要新增的科室
            List<DeptDictEntity> deptsToSave = remoteDeptList.stream()
                    .filter(deptDo -> deptDo != null && !existingDeptCodes.contains(deptDo.getDeptCode()))
                    .map(this::convertToEntity) // 提取转换逻辑到独立方法
                    .collect(Collectors.toList());

            if (CollectionUtils.isEmpty(deptsToSave)) {
                log.info("没有新的科室信息需要同步，任务结束。");
                return;
            }
            log.info("本次需要新增 {} 个科室信息到本地数据库。", deptsToSave.size());

            // 4. 批量插入新科室信息
            // 使用 Mybatis-Plus 的 saveBatch 方法，并指定批次大小
            this.saveBatch(deptsToSave, BATCH_SIZE);

            log.info("--- 科室字典数据同步完成。成功新增 {} 条记录，总耗时：{} ms ---",
                    deptsToSave.size(), System.currentTimeMillis() - startTime);

        } catch (Exception e) {
            log.error("同步科室字典数据时发生异常: ", e);
            throw e; // 抛出异常，触发事务回滚，并让调用方感知
        }
    }

    /**
     * 从远程服务获取并转换科室列表
     * 此方法主要用于需要获取最新列表但不入库的场景。
     *
     * @return 转换后的 DeptDictEntity 列表
     */
    public List<DeptDictEntity> getRemoteDeptDictList() {
        log.info("从远程服务获取科室列表...");
        R<List<DeptDictDo>> remoteDeptListR = remoteHisCommonService.deptListByDB();

        if (remoteDeptListR == null || !R.isSuccess(remoteDeptListR) || CollectionUtils.isEmpty(remoteDeptListR.getData())) {
            log.warn("从远程服务获取科室列表失败或返回为空。");
            return Collections.emptyList(); // 返回空列表而非null，增强调用方代码健壮性
        }

        List<DeptDictDo> remoteDeptList = remoteDeptListR.getData();
        log.info("从远程服务获取到 {} 个科室信息。", remoteDeptList.size());

        return remoteDeptList.stream()
                .filter(Objects::nonNull)
                .filter(deptDo -> deptDo.getDeptName() != null && !deptDo.getDeptName().trim().isEmpty())
                .map(this::convertToEntity)
                .collect(Collectors.toList());
    }

    public void exportToTxt() {
        List<DeptDictEntity> deptList = baseMapper.selectAll();
        // 1. 定义文件路径和名称
        File file = new File("d:/target/dept.txt");

        // 2. 检查并创建父目录
        File parentDir = file.getParentFile();
        if (parentDir != null && !parentDir.exists()) {
            boolean dirCreated = parentDir.mkdirs();
            if (dirCreated) {
                log.info("成功创建父目录: " + parentDir.getAbsolutePath());
            } else {
                log.error("创建父目录失败: " + parentDir.getAbsolutePath());
                throw new RuntimeException("无法创建导出文件的父目录，请检查权限。");
            }
        }

        // 3. 使用 try-with-resources 创建文件输出流和 BufferedWriter
        //    这里直接使用 FileOutputStream(file) 来指向我们定义的文件
        try (BufferedWriter writer = new BufferedWriter(
                new OutputStreamWriter(new FileOutputStream(file), "UTF-8"))) {

            // 4. 写入表头
//            writer.write("dept_code" + "\t" + "dept_name");
//            writer.newLine();

            // 5. 遍历数据并写入文件
            for (DeptDictEntity dept : deptList) {
                // 处理可能为null的字段
                String deptCode = dept.getDeptCode() != null ? dept.getDeptCode() : "";
                String deptName = dept.getDeptName() != null ? dept.getDeptName() : "";
                writer.write(deptCode + "\t" + deptName);
                writer.newLine();
            }

            writer.flush();
            log.info("数据导出成功！文件已保存至: " + file.getAbsolutePath());

        } catch (UnsupportedEncodingException e) {
            log.error("写入文件失败，原因：不支持的编码格式", e);
            throw new RuntimeException("导出文件失败，不支持的编码格式", e);
        } catch (IOException e) {
            log.error("写入文件失败，原因：" + e.getMessage(), e);
            throw new RuntimeException("导出文件失败，请检查文件路径或权限", e);
        }
    }

    /**
     * 将 DeptDictDo 转换为 DeptDictEntity
     */
    private DeptDictEntity convertToEntity(DeptDictDo deptDo) {
        // 假设 DeptDictEntity 有一个合适的构造函数或 setter 方法
        return new DeptDictEntity(deptDo.getDeptCode(), deptDo.getDeptName());
    }
}